
package com.trydofor.id.a9ic;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;

import com.trydofor.id.core.Range;

/**
 * A9ic Helper
 * 
 * @author Shi Rongjiu (www.trydofor.com)
 * @since 0.9
 */
@Immutable
public final class A9icHelper {
    
    /**
     */
    private A9icHelper() {
    }
    
    /**
     * get the A9IC BLINK range by worker.
     * 
     * @param worker the minimum worker
     * @return @Nonnull the Range
     */
    @Nonnull
    public static Range getRangeBlink(int worker) {
        long minBlink;
        long maxBlink;
        
        if (worker == 0) {
            minBlink = 1L << 20;
            maxBlink = (1L << 32) - 1;
        }
        else {
            long wk = (long) worker;
            minBlink = ((wk << 20) | ((1 << 20) - 1)) + 1;
            maxBlink = ((wk << 52) | (1 << 20)) - 1;
        }
        
        return new Range(minBlink, maxBlink);
    }
    
    /**
     * get the Lower A9IC range by worker.
     * 
     * @param worker the minimum worker
     * @return @Nonnull the Range
     */
    @Nonnull
    public static Range getRangeLower(int worker) {
        A9IC min = new A9IC(worker, A9IC.getRangeOfSerialLower().minimum());
        A9IC max = new A9IC(worker, A9IC.getRangeOfSerialLower().maximum());
        return new Range(min.longValue(), max.longValue());
    }
    
    /**
     * get the upper A9IC range by worker.
     * 
     * @param worker the minimum worker
     * @return @Nonnull the Range
     */
    @Nonnull
    public static Range getRangeUpper(int worker) {
        A9IC min = new A9IC(worker, A9IC.getRangeOfSerialUpper().minimum());
        A9IC max = new A9IC(worker, A9IC.getRangeOfSerialUpper().maximum());
        return new Range(min.longValue(), max.longValue());
    }
    
    /**
     * get the upper offset between workers.
     * a9ic(new worker) = a9ic(old worker) + offset.
     * 
     * @param worker the candidate worker
     * @param toWorker new worker
     * @return offset
     */
    public static long getRangeOffsetUpper(int worker, int toWorker) {
        return (toWorker - worker) * (1L << (A9IC.getBitOfSerialUpper()));
    }
    
    /**
     * get the lower offset between workers.
     * a9ic(new worker) = a9ic(old worker) + offset.
     * 
     * @param worker the candidate worker
     * @param toWorker new worker
     * @return offset
     */
    public static long getRangeOffsetLower(int worker, int toWorker) {
        return (toWorker - worker) * (1L << (A9IC.getBitOfSerialLower()));
    }
}
